package com.atguigu.gmall.product.service.impl;

import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.common.execption.GmallException;
import com.atguigu.gmall.common.result.ResultCodeEnum;
import com.atguigu.gmall.feign.search.SearchFeignClient;
import com.atguigu.gmall.product.entity.*;
import com.atguigu.gmall.product.service.*;
import com.atguigu.gmall.product.vo.CategoryPath;
import com.atguigu.gmall.product.vo.SkuDataVo;
import com.atguigu.gmall.search.entity.Goods;
import com.atguigu.gmall.search.entity.SearchAttr;
import com.atguigu.starter.cache.service.BitMapService;
import com.atguigu.starter.cache.service.CacheService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.atguigu.gmall.product.mapper.SkuInfoMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

/**
 * @author lfy
 * @description 针对表【sku_info(库存单元表)】的数据库操作Service实现
 * @createDate 2023-07-11 15:27:09
 */
@Slf4j
@Service
public class SkuInfoServiceImpl extends ServiceImpl<SkuInfoMapper, SkuInfo>
        implements SkuInfoService {

    @Autowired
    SkuImageService skuImageService;

    @Autowired
    SkuAttrValueService skuAttrValueService;

    @Autowired
    SkuSaleAttrValueService skuSaleAttrValueService;

    @Autowired
    SkuInfoMapper skuInfoMapper;

    @Autowired
    StringRedisTemplate redisTemplate;

    @Autowired
    SearchFeignClient searchFeignClient;

    @Autowired
    BaseTrademarkService baseTrademarkService;

    @Autowired
    BaseCategory1Service baseCategory1Service;

    @Autowired
    BitMapService bitMapService;

    @Autowired
    CacheService cacheService;

    @Autowired
    ThreadPoolExecutor executor;



    @Transactional
    @Override
    public void saveSkuInfo(SkuDataVo skuData) {
        //1、sku基本数据 保存到 sku_info
        SkuInfo skuInfo = new SkuInfo();
        BeanUtils.copyProperties(skuData, skuInfo);
        this.save(skuInfo);

        //获取到 sku 的自增id值
        Long skuId = skuInfo.getId();

        //2、sku图片数据 保存到 sku_image
        List<SkuImage> skuImages = skuData.getSkuImageList()
                .stream()
                .map(item -> {
                    SkuImage image = new SkuImage();
                    //数据转换
                    BeanUtils.copyProperties(item, image);
                    image.setSkuId(skuId); //id回填
                    return image;
                }).collect(Collectors.toList());
        skuImageService.saveBatch(skuImages);

        //3、sku平台属性名和值 保存到 sku_attr_value
        List<SkuAttrValue> skuAttrValues = skuData.getSkuAttrValueList()
                .stream()
                .map(item -> {
                    SkuAttrValue attrValue = new SkuAttrValue();
                    BeanUtils.copyProperties(item, attrValue);
                    attrValue.setSkuId(skuId);//回填
                    return attrValue;
                }).collect(Collectors.toList());
        skuAttrValueService.saveBatch(skuAttrValues);


        //4、sku销售属性数据 保存到 sku_sale_attr_value
        List<SkuSaleAttrValue> skuSaleAttrValues = skuData.getSkuSaleAttrValueList()
                .stream()
                .map(item -> {
                    SkuSaleAttrValue skuSaleAttrValue = new SkuSaleAttrValue();
                    BeanUtils.copyProperties(item, skuSaleAttrValue);
                    skuSaleAttrValue.setSkuId(skuId);
                    skuSaleAttrValue.setSpuId(skuData.getSpuId());
                    return skuSaleAttrValue;
                }).collect(Collectors.toList());
        skuSaleAttrValueService.saveBatch(skuSaleAttrValues);

    }

    @Override
    public void onSale(Long skuId) {
        //1、修改数据库上下架状态
        this.lambdaUpdate()
                .set(SkuInfo::getIsSale, "1")
                .eq(SkuInfo::getId, skuId)
                .update();

        //2、准备Goods数据
        Goods goods = getSkuInfoForGoods(skuId);

        //3、远程调用 上架方法
        searchFeignClient.up(goods);

        //4、上架需要更新位图
        bitMapService.setbit(RedisConst.BITMAP_SKUID,skuId,true);
    }


    public Goods getSkuInfoForGoods(Long skuId) {

        Goods goods = new Goods();
        CompletableFuture<SkuInfo> skuInfoFuture = CompletableFuture
                .supplyAsync(() -> {
            //1、skuinfo 信息
            SkuInfo info = getById(skuId);
            goods.setId(info.getId());
            goods.setDefaultImg(info.getSkuDefaultImg());
            goods.setTitle(info.getSkuName());
            goods.setPrice(info.getPrice().doubleValue());
            goods.setCreateTime(new Date());
            return info;
        }, executor);


        //2、品牌信息
        CompletableFuture<Void> tmFuture = skuInfoFuture.thenAcceptAsync(res -> {
            Long tmId = res.getTmId();
            BaseTrademark trademark = baseTrademarkService.getById(tmId);
            goods.setTmId(trademark.getId());
            goods.setTmName(trademark.getTmName());
            goods.setTmLogoUrl(trademark.getLogoUrl());
        },executor);



        //3、 sku的分类层级信息
        CompletableFuture<Void> categoryFuture = skuInfoFuture.thenAcceptAsync(res -> {
            Long category3Id = res.getCategory3Id();
            CategoryPath path = baseCategory1Service.getCategoryPath(category3Id);
            goods.setCategory1Id(path.getCategory1Id());
            goods.setCategory1Name(path.getCategory1Name());
            goods.setCategory2Id(path.getCategory2Id());
            goods.setCategory2Name(path.getCategory2Name());
            goods.setCategory3Id(path.getCategory3Id());
            goods.setCategory3Name(path.getCategory3Name());
            goods.setHotScore(0L);
        },executor);



        //4、sku的平台属性名和值信息
        CompletableFuture<Void> attrFuture = CompletableFuture.runAsync(() -> {
            List<SearchAttr> searchAttrs = skuAttrValueService.getSkuAttrValues(skuId);
            goods.setAttrs(searchAttrs);
        }, executor);

        CompletableFuture.allOf(tmFuture,categoryFuture,attrFuture).join();

        return goods;
    }

    @Override
    public void checkSkuSaveData(SkuDataVo skuData) {
        //1、检查这个销售属性在数据库中有没有
        String valuesId = skuData.getSkuSaleAttrValueList().stream()
                .map(item -> item.getSaleAttrValueId().toString())
                .reduce((o1, o2) -> o1 + "," + o2)
                .get();

        Long count = skuInfoMapper.checkSkuValues(skuData.getSpuId(),valuesId);

        if(count > 0){
            //发现业务非预期的问题，就直接抛出业务错误枚举对应的异常
            throw new GmallException(ResultCodeEnum.SKU_HAS_EXIST);
        }

    }

    @Override
    public void cancleSale(Long skuId) {
        this.lambdaUpdate()
                .set(SkuInfo::getIsSale, "0")
                .eq(SkuInfo::getId, skuId)
                .update();
        //2、ES进行上下架
        searchFeignClient.down(skuId);

        //3、位图下架
        bitMapService.setbit(RedisConst.BITMAP_SKUID,skuId,false);

        //4、清除数据缓存
        cacheService.delayDoubleDelete(RedisConst.SKUINFO+skuId);
    }

    @Override
    public BigDecimal getRealTimePrice(Long skuId) {

        return skuInfoMapper.getRealTimePrice(skuId);
    }


    @Override
    public void initSkuidBitMap() {
        //1、查询所有的skuid
        List<Long> skuIds = skuInfoMapper.getSkuIds();

        //2、去bitmap占位
        skuIds.stream()
                .forEach(item -> {
                    redisTemplate.opsForValue().setBit(RedisConst.BITMAP_SKUID, item, true);
                });
        log.info("skuid位图初始化完成，总计：【{}】个商品",skuIds.size());

    }
}




